import json
import time

from pymodbus.client.sync import ModbusSerialClient
import znReplaying
import requests
print(znReplaying.replayingVars)
class TZnRtu:
    def __init__(self):
        self.config={
            "comPort":"COM16",
            "baudRate":9600,
            "parity":"E",
            "stopBit":1 ,
            "dataBit":8 ,
            "apiUrl":"http://hh.hhdata.cn:31297/db/ms/query",
            "apiDbKey":"znv2",
            "apiDbPath":"zn2024/modbus_rtu/relaying",
            "postUrl":"http://hh.hhdata.cn:31297/zn/svr/postData",
        }
        self.devs= {}
        self.tasks=[]
        self.loopTasks =[]
        self.unLoopTasks =[]
        self.dps=[]
        self.dpDict ={}
        self.serialCom = None
    def connect(self):
        res = False
        try:
# 配置串口参数
            COM_PORT = self.config['comPort']  # 串口号（Windows系统可能是COM1、COM2等）
            BAUD_RATE = self.config['baudRate']  # 波特率
            PARITY = self.config['parity']  # 奇偶校验（'N'表示无校验，'E'表示偶校验，'O'表示奇校验）
            STOP_BITS = self.config['stopBit']  # 停止位
            DATA_BITS = self.config['dataBit']  # 数据位
            client = ModbusSerialClient(method='rtu', port=COM_PORT, baudrate=BAUD_RATE,parity=PARITY, stopbits=STOP_BITS, bytesize=DATA_BITS)
            self.serialCom = client
            res = True
        except Exception as er:
            print(er)
        return  res

    def loadDatas(self):
        try:
            params ={
                "dbKey_":self.config['apiDbKey'],
                "dbPath_":self.config['apiDbPath']
            }
            url= self.config['apiUrl']
            resp = requests.post(url , data = json.dumps(params))
            datas = json.loads(resp.text)['result']
            for dev in datas[0]:
                self.devs[dev['devCode']] = dev
            self.tasks = datas[1]
            self.dps = datas[2]
            for dp in self.dps:
                self.dpDict[dp['dpId']] = dp
                #dp['rate'] = float(dp['rateStr'])
                #dp['threshold'] = float(dp['thresholdStr'])
                dp['values']={
                    "state":0 ,
                    "changed":0 ,
                    "old":{
                        "v":0,
                        "tm":0
                    },
                    "new":{
                        "v":0,
                        "tm":0
                    },
                }
            for task in self.tasks:
                task['dps']=[]
                for dp in self.dps:
                    flag = task['devCode']==dp['devCode']  and task['taskId'] == dp['taskId']
                    if flag:
                        task['dps'].append(dp)
                if task['loopFlag']>0:
                    self.loopTasks.append(task)
                else:
                    self.unLoopTasks.append(task)
            print(datas)
        except Exception as er :
            print(er)

    def exectask(self , task ):
        try:
            addr = task['fromAddr']
            regCount = task['regCount']
            unitId = task['unitId']
            response = self.serialCom.read_holding_registers(address=addr, count=regCount, unit=unitId)
            readFlag = response.isError()
            if readFlag:
                print("读取失败：", response)
            else:
                print("保持寄存器的值：", response.registers)
                for dp in task['dps']:
                    try:
                        dp['values']['old']['v'] = dp['values']['new']['v']
                        dp['values']['old']['tm'] = dp['values']['new']['tm']
                        dp['values']['new']['tm'] = time.time()

                        regIndex = dp['regAddr'] - task['fromAddr']
                        regValue = response.registers[regIndex]
                        dpValue = 0
                        if dp['bitIndex']>=0 and dp['bitIndex']<16:
                            dpValue = 0 if (pow(2,dp['bitIndex'])  & regValue==0 ) else 1
                        elif dp['bitIndex']==777:
                            s = regValue & 0x8000 >0
                            v = regValue
                            if s :
                                v = 0xFFFF - regValue + 1
                            rate = 1 if dp['rate'] == 1 else dp['rate']
                            dpValue = (0x7fff & v)  * rate
                        elif dp['bitIndex']==888:
                            vH = response.registers[regIndex]
                            vL = response.registers[regIndex-1]
                            v= (vH << 16) + vL
                            s = v & 0x80000000
                            if s==0:
                                dpValue = v
                            else:
                                dpValue = 0xffffffff- v + 1
                            rate = 1 if dp['rate'] == 1 else dp['rate']
                            dpValue = dpValue * rate
                        else:
                            dpValue = regValue if dp['rate']==1 else regValue * dp['rate']
                        dp['values']['new']['v'] = dpValue

                        changed = 0
                        if dp['values']['state'] == 0 :
                            dp['values']['state'] = 1
                            changed =1
                        else:
                            if dp['thresholdType']=='N01' and not (dp['values']['old']['v'] == dp['values']['new']['v']):
                                changed = 1
                            elif dp['thresholdType']=='N02':
                                if dp['values']['old']['v']==0 and dp['values']['old']['v']!=dp['values']['new']['v']:
                                    changed = 1
                                else:
                                    diff = abs(dp['values']['new']['v'] - dp['values']['old']['v'])
                                    oldValue = abs(dp['values']['old']['v'])
                                    dlt = 0.01 * dp['threshold']
                                    if oldValue * dlt <  diff:
                                        changed = 1
                        dp['values']['changed'] = changed
                    except Exception as eer:
                        print(eer)



        except Exception as er:
            print(er)

    def getChangedDps(self):
        res ={}
        try:
            for dp in self.dps:
                if dp['values']['changed']>0:
                    k = dp['dpId']
                    v = dp['values']['new']['v']
                    res[k] = v
        except Exception as er:
            print(er)
        return  res
    def saveDps(self, dps):
        try:
            pass
        except Exception as er:
            print(er)
    def postDps(self , dps):
        try:
            pass
        except Exception as er:
            print(er)
    def start(self):
        try:
            connFlag = self.connect()
            if connFlag:
                for task in self.unLoopTasks:
                    self.exectask(task)
                while 1>0 :

                    for task in self.loopTasks:
                        self.exectask(task)

                    changedDps = self.getChangedDps()
                    if len(changedDps.keys())>0:
                        url = self.config['postUrl']
                        resp = requests.post(url , changedDps)
                        for dp in self.dps:
                            dp['values']['changed'] =0
                        print(resp , changedDps)

                    time.sleep(60*10)

            else:
                print("connect comPort fail.")
        except Exception as er:
            print(er)

znRtu = TZnRtu()
znRtu.loadDatas()
znRtu.start()


# 配置串口参数
COM_PORT = 'COM16'  # 串口号（Windows系统可能是COM1、COM2等）
BAUD_RATE = 9600  # 波特率
PARITY = 'E'  # 奇偶校验（'N'表示无校验，'E'表示偶校验，'O'表示奇校验）
STOP_BITS = 1  # 停止位
DATA_BITS = 8  # 数据位

# 创建Modbus RTU客户端
client = ModbusSerialClient(method='rtu', port=COM_PORT, baudrate=BAUD_RATE,
                            parity=PARITY, stopbits=STOP_BITS, bytesize=DATA_BITS)

# 连接到Modbus设备
if client.connect():
    print("设备连接成功")

    # 读取保持寄存器的值（示例地址为1，寄存器地址为0，读取一个寄存器）
    response = client.read_holding_registers(address=0x0200, count=82, unit=11)
    if response.isError():
        print("读取失败：", response)
    else:
        print("保持寄存器的值：", response.registers)

    # 关闭连接
    client.close()
else:
    print('COM is error.')
